package cn.yj.core.business.service;

import cn.yj.annotation.pagehelper.page.Page;
import cn.yj.api.FileUploadHandler;
import cn.yj.cgs.dba.entity.*;
import cn.yj.cgs.dba.entity.vo.IntegralGoodBuyVo;
import cn.yj.cgs.dba.entity.vo.IntegralGoodVo;
import cn.yj.cgs.dba.mapper.ImagesMapper;
import cn.yj.cgs.dba.mapper.IntegralGoodsMapper;
import cn.yj.cgs.dba.mapper.IntegralGoodsTypeMapper;
import cn.yj.common.AppExecutor;
import cn.yj.common.Enums;
import cn.yj.common.UUIdUtils;
import cn.yj.common.config.BeanTool;
import cn.yj.commons.StringPools;
import cn.yj.commons.utils.BigDecimalUtils;
import cn.yj.commons.utils.StringUtils;
import cn.yj.core.business.service.iservice.IIntegralGoodsService;
import cn.yj.core.business.service.iservice.IMessageService;
import cn.yj.core.business.service.iservice.IUserAddressService;
import cn.yj.email.EmailType;
import cn.yj.email.handle.DefaultEmailHandler;
import cn.yj.email.handle.Email;
import cn.yj.entity.Base64Entity;
import cn.yj.params.check.annotation.CheckObjectValue;
import cn.yj.params.check.annotation.KeyValue;
import cn.yj.params.check.annotation.Require;
import cn.yj.tools.exception.ServiceException;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

/**
 * @author 永健
 * @since 2021-05-09 13:02
 */
@Service
public class IntegralGoodsService extends ServiceImpl<IntegralGoodsMapper, IntegralGoods> implements IIntegralGoodsService {

    private final static Logger log = LoggerFactory.getLogger(IntegralGoodsService.class);

    @Resource
    private ImagesMapper imagesMapper;

    @Resource
    private IUserAddressService addressService;

    @Resource
    private IntegralService integralService;

    @Resource
    private IntegralGoodsTypeMapper integralGoodsTypeMapper;

    @Resource
    private UserIntegralGoodsService userGoodsService;

    @Override
    public Page<IntegralGoods> pageList(Map<String, Object> prams, Page<IntegralGoods> page) {
        baseMapper.findList(prams, page);
        return page;
    }

    @CheckObjectValue(keyValue = @KeyValue(type = IntegralGoodVo.class, name = {"goodName", "price", "typeNo",
            "mainImgBase64", "content"}))
    @Override
    public boolean addGoods(IntegralGoodVo integralGoodVo) {
        final ExecutorService executorService = getExecutors(Enums.Common.ONE);
        final CyclicBarrier cyclicBarrier = new CyclicBarrier(2);

        executorService.execute(() -> handlerImg(cyclicBarrier, integralGoodVo));
        try {
            cyclicBarrier.await();
        } catch (InterruptedException | BrokenBarrierException e) {
            e.printStackTrace();
        }
        executorService.shutdown();

        String goodNo = UUIdUtils.getCode();

        insertImages(integralGoodVo.getSwiperUrl(), goodNo);

        IntegralGoods integralGoods = new IntegralGoods();
        BeanUtils.copyProperties(integralGoodVo, integralGoods);
        integralGoods.setGoodsNo(goodNo);
        integralGoods.setMainImgUrl(integralGoodVo.getMainImgBase64());

        return baseMapper.insert(integralGoods) > Enums.Common.ZERO;
    }


    @CheckObjectValue(keyValue = @KeyValue(type = IntegralGoodVo.class, name = {"goodNo", "goodName", "price",
            "typeNo", "mainImgBase64", "content", "status"}))
    @Override
    public boolean updateGoodsByCode(IntegralGoodVo integralGoodVo) {
        ExecutorService executorService = getExecutors(Enums.Common.ONE);
        CyclicBarrier cyclicBarrier = new CyclicBarrier(2);

        // 删除旧的
        List<String> swiper = StringUtils.isNotBlank(integralGoodVo.getSwiper())?
                Arrays.asList(integralGoodVo.getSwiper().split("&&")) : new ArrayList<>();

        swiper.forEach(imgUrl -> imagesMapper.delete(new UpdateWrapper<Images>().lambda().eq(Images::getImgUrl,
                imgUrl)));

        executorService.execute(() -> handlerImg(cyclicBarrier, integralGoodVo));
        try {
            cyclicBarrier.await();
        } catch (InterruptedException | BrokenBarrierException e) {
            e.printStackTrace();
        }
        executorService.shutdown();

        insertImages(integralGoodVo.getSwiperUrl(), integralGoodVo.getGoodsNo());

        IntegralGoods integralGoods = new IntegralGoods();
        BeanUtils.copyProperties(integralGoodVo, integralGoods);
        integralGoods.setMainImgUrl(integralGoodVo.getMainImgBase64());
        integralGoods.setStatus(Enums.IntegralGood.STATUS.valueOf(integralGoodVo.getStatus()));

        return baseMapper.update(integralGoods, updateLambda().eq(IntegralGoods::getGoodsNo,
                integralGoods.getGoodsNo())) > Enums.Common.ZERO;
    }

    @CheckObjectValue(keyValue = @KeyValue(type = IntegralGoodVo.class, name = {"goodsNo", "userCode", "num",
            "addressId"}))
    @Transactional
    @Override
    public boolean goBuy(IntegralGoodBuyVo buyVo) {
        String goodNo = buyVo.getGoodsNo();

        if (buyVo.getNum() <= Enums.Common.ZERO) {
            throw new ServiceException("数量必须大于1");
        }

        // 加锁 防止库存减超
        IntegralGoods integralGoods = baseMapper.selectByNoForUpdate(goodNo);

        // 地址校验
        if (!addressService.exitsById(buyVo.getAddressId())) {
            throw new ServiceException("请选择收货地址");
        }

        // 商品存在检查
        if (StringUtils.isNull(goodNo)) {
            throw new ServiceException("商品编号不存在");
        }

        // 商品状态检查
        Enums.IntegralGood.STATUS status = integralGoods.getStatus();
        if (status != Enums.IntegralGood.STATUS.ON) {
            throw new ServiceException("商品已下架");
        }

        // 库存判断
        if (integralGoods.getStock() < buyVo.getNum()) {
            throw new ServiceException(String.format("库存数量不足：%s", integralGoods.getStock()));
        }

        // 校验个人积分是否充足
        BigDecimal buyAmount = BigDecimalUtils.mul(new BigDecimal(buyVo.getNum()), integralGoods.getIntegralPrice());

        // 创建订单
        UserIntegralGoods userIntegralGoods = new UserIntegralGoods();
        BeanUtils.copyProperties(integralGoods, userIntegralGoods);
        userIntegralGoods.setNum(buyVo.getNum());
        userIntegralGoods.setAmount(buyAmount);
        userIntegralGoods.setAddressId(buyVo.getAddressId());
        userIntegralGoods.setUserGoodsNo(UUIdUtils.getCode());
        userIntegralGoods.setUserCode(buyVo.getUserCode());
        userGoodsService.save(userIntegralGoods);

        // 减积分/积分流水
        integralService.updateIntegral(buyVo.getUserCode(), buyAmount, false, Enums.IntegralWater.SOURCE.EXCHANGE,
                null);

        // 减库存
        integralGoods.setStock(integralGoods.getStock() - buyVo.getNum());
        if (baseMapper.updateById(integralGoods) <= Enums.Common.ZERO) {
            throw new ServiceException("置换失败，请再试试");
        }


        AppExecutor.exec(() -> {
            BeanTool.getBean(IMessageService.class).notice(new Message("您使用积分兑换商品【"+integralGoods.getGoodName()+"】，已成功兑换。可到 积分-兑换记录里查看", "积分使用通知", buyVo.getUserCode()));

            Email email = new Email(EmailType.商品兑换通知,
                    "用户使用积分兑换商品<br/> 用户编码：" + buyVo.getUserCode() + " <br/>商品名称：" + integralGoods.getGoodName());
            email.setRecEmail(email.getFrom());
            BeanTool.getBean(DefaultEmailHandler.class).sendEmail(email);
        });

        return true;
    }

    private void handlerImg(CyclicBarrier cyclicBarrier, IntegralGoodVo integralGoodVo) {
        String mainImgBase64 = integralGoodVo.getMainImgBase64();
        List<String> swipers = StringUtils.isNotBlank(integralGoodVo.getSwiper())?
                Arrays.asList(integralGoodVo.getSwiper().split("&&")) : new ArrayList<>();
        List<String> swipersUrl = new ArrayList<>();

        try {

            if (StringUtils.isNotBlank(mainImgBase64) && !mainImgBase64.startsWith("data")) {
                Base64Entity base64Entity = new Base64Entity(mainImgBase64, Enums.Minio.Bucket.goods.name().concat(
                        "/").concat(UUIdUtils.getCode().concat(StringPools.JPG)));
                base64Entity.setContentType(Enums.Minio.ContentType.IMG.getContentType());
                String upload = FileUploadHandler.getInstant().upload(base64Entity);
                integralGoodVo.setMainImgBase64(upload);
            }

            swipers.forEach(base64 -> {
                if (StringUtils.isNotBlank(mainImgBase64) && !mainImgBase64.startsWith("data")) {
                    try {
                        Base64Entity base64Entity = new Base64Entity(mainImgBase64,
                                Enums.Minio.Bucket.goods.name().concat("/").concat(UUIdUtils.getCode().concat(StringPools.JPG)));
                        base64Entity.setContentType(Enums.Minio.ContentType.IMG.getContentType());
                        String swiper = FileUploadHandler.getInstant().upload(base64Entity);
                        swipersUrl.add(swiper);
                    } catch (Exception e) {
                        log.error("轮播图上传失败：{}", e.getMessage());
                        throw new ServiceException("轮播图上传失败,请重试");
                    }
                }
            });
            integralGoodVo.setSwiperUrl(swipersUrl);
            cyclicBarrier.await();
        } catch (Exception e) {
            log.error("主图上传失败：{}", e.getMessage());
            throw new ServiceException("主图上传失败,请重试");
        }
    }

    private void insertImages(List<String> swiper, String goodNo) {
        // 轮播图上传
        swiper.forEach(url -> {
            Images images = new Images();
            images.setCode(goodNo);
            images.setType(Enums.Images.TYPE.SWIPER.name());
            images.setImgUrl(url);
            imagesMapper.insert(images);
        });
    }

    private ExecutorService getExecutors(int num) {
        return Executors.newFixedThreadPool(num);
    }

    @Override
    public List<IntegralGoodsType> getGoodsType() {
        return integralGoodsTypeMapper.selectList(new QueryWrapper<IntegralGoodsType>().lambda().orderByAsc(IntegralGoodsType::getSort));
    }

    @Override
    public IntegralGoods getDetail(@Require String goodsNo) {
        IntegralGoods integralGoods = super.getOne(queryLambda().eq(IntegralGoods::getGoodsNo, goodsNo));
        if (StringUtils.isNull(integralGoods)) {
            throw new ServiceException("该积分商品不存在");
        }
        List<String> images = imagesMapper.selectList(new QueryWrapper<Images>().lambda().eq(Images::getCode,
                goodsNo).eq(Images::getType, Enums.Images.TYPE.SWIPER.name())).stream().map(images1 -> images1.getImgUrl()).collect(Collectors.toList());
        images.add(integralGoods.getMainImgUrl());
        integralGoods.setSwiper(images);
        return integralGoods;
    }

    @Transactional
    @Override
    public IntegralGoods selectByGoodsNoForUpdate(String goodsNo) {
        return baseMapper.selectByNoForUpdate(goodsNo);
    }
}
